/*
    MANGO Multimedia Development Platform
    Copyright (C) 2012-2019 Twilight Finland 3D Oy Ltd. All rights reserved.
*/
#include <mango/core/crc32.hpp>
#include <mango/core/exception.hpp>
#include <mango/core/bits.hpp>
#include <mango/core/endian.hpp>

#if defined(MANGO_ENABLE_SSE4_2)

    #define MANGO_HARDWARE_CRC32C

#elif defined(__ARM_FEATURE_CRC32)

    #define MANGO_HARDWARE_CRC32
    #define MANGO_HARDWARE_CRC32C

#endif

namespace
{
    using namespace mango;

#if !defined(MANGO_HARDWARE_CRC32)

    // //////////////////////////////////////////////////////////
    // Copyright (c) 2014 Stephan Brumme. All rights reserved.
    // see http://create.stephan-brumme.com/disclaimer.html
    //

    // Original implementaiton of Intel slice-by-8 by Stephan Brumme. Adapted for MANGO in June 2016.

    constexpr u32 g_crc32_table[] =
    {
        0x00000000,0x77073096,0xee0e612c,0x990951ba,0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,
        0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,
        0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,
        0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,
        0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,
        0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940,0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,
        0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f,
        0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d,
        0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,
        0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01,
        0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,
        0x65b0d9c6,0x12b7e950,0x8bbeb8ea,0xfcb9887c,0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,
        0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2,0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,
        0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,
        0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,0x5768b525,0x206f85b3,0xb966d409,0xce61e49f,
        0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,0x59b33d17,0x2eb40d81,0xb7bd5c3b,0xc0ba6cad,
        0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,0xead54739,0x9dd277af,0x04db2615,0x73dc1683,
        0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,
        0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,
        0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc,0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,
        0xd6d6a3e8,0xa1d1937e,0x38d8c2c4,0x4fdff252,0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,
        0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79,
        0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,
        0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,
        0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,
        0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,
        0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e,0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,
        0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,
        0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,
        0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,
        0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,0xbad03605,0xcdd70693,0x54de5729,0x23d967bf,
        0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d,
        
        0x00000000,0x191b3141,0x32366282,0x2b2d53c3,0x646cc504,0x7d77f445,0x565aa786,0x4f4196c7,
        0xc8d98a08,0xd1c2bb49,0xfaefe88a,0xe3f4d9cb,0xacb54f0c,0xb5ae7e4d,0x9e832d8e,0x87981ccf,
        0x4ac21251,0x53d92310,0x78f470d3,0x61ef4192,0x2eaed755,0x37b5e614,0x1c98b5d7,0x05838496,
        0x821b9859,0x9b00a918,0xb02dfadb,0xa936cb9a,0xe6775d5d,0xff6c6c1c,0xd4413fdf,0xcd5a0e9e,
        0x958424a2,0x8c9f15e3,0xa7b24620,0xbea97761,0xf1e8e1a6,0xe8f3d0e7,0xc3de8324,0xdac5b265,
        0x5d5daeaa,0x44469feb,0x6f6bcc28,0x7670fd69,0x39316bae,0x202a5aef,0x0b07092c,0x121c386d,
        0xdf4636f3,0xc65d07b2,0xed705471,0xf46b6530,0xbb2af3f7,0xa231c2b6,0x891c9175,0x9007a034,
        0x179fbcfb,0x0e848dba,0x25a9de79,0x3cb2ef38,0x73f379ff,0x6ae848be,0x41c51b7d,0x58de2a3c,
        0xf0794f05,0xe9627e44,0xc24f2d87,0xdb541cc6,0x94158a01,0x8d0ebb40,0xa623e883,0xbf38d9c2,
        0x38a0c50d,0x21bbf44c,0x0a96a78f,0x138d96ce,0x5ccc0009,0x45d73148,0x6efa628b,0x77e153ca,
        0xbabb5d54,0xa3a06c15,0x888d3fd6,0x91960e97,0xded79850,0xc7cca911,0xece1fad2,0xf5facb93,
        0x7262d75c,0x6b79e61d,0x4054b5de,0x594f849f,0x160e1258,0x0f152319,0x243870da,0x3d23419b,
        0x65fd6ba7,0x7ce65ae6,0x57cb0925,0x4ed03864,0x0191aea3,0x188a9fe2,0x33a7cc21,0x2abcfd60,
        0xad24e1af,0xb43fd0ee,0x9f12832d,0x8609b26c,0xc94824ab,0xd05315ea,0xfb7e4629,0xe2657768,
        0x2f3f79f6,0x362448b7,0x1d091b74,0x04122a35,0x4b53bcf2,0x52488db3,0x7965de70,0x607eef31,
        0xe7e6f3fe,0xfefdc2bf,0xd5d0917c,0xcccba03d,0x838a36fa,0x9a9107bb,0xb1bc5478,0xa8a76539,
        0x3b83984b,0x2298a90a,0x09b5fac9,0x10aecb88,0x5fef5d4f,0x46f46c0e,0x6dd93fcd,0x74c20e8c,
        0xf35a1243,0xea412302,0xc16c70c1,0xd8774180,0x9736d747,0x8e2de606,0xa500b5c5,0xbc1b8484,
        0x71418a1a,0x685abb5b,0x4377e898,0x5a6cd9d9,0x152d4f1e,0x0c367e5f,0x271b2d9c,0x3e001cdd,
        0xb9980012,0xa0833153,0x8bae6290,0x92b553d1,0xddf4c516,0xc4eff457,0xefc2a794,0xf6d996d5,
        0xae07bce9,0xb71c8da8,0x9c31de6b,0x852aef2a,0xca6b79ed,0xd37048ac,0xf85d1b6f,0xe1462a2e,
        0x66de36e1,0x7fc507a0,0x54e85463,0x4df36522,0x02b2f3e5,0x1ba9c2a4,0x30849167,0x299fa026,
        0xe4c5aeb8,0xfdde9ff9,0xd6f3cc3a,0xcfe8fd7b,0x80a96bbc,0x99b25afd,0xb29f093e,0xab84387f,
        0x2c1c24b0,0x350715f1,0x1e2a4632,0x07317773,0x4870e1b4,0x516bd0f5,0x7a468336,0x635db277,
        0xcbfad74e,0xd2e1e60f,0xf9ccb5cc,0xe0d7848d,0xaf96124a,0xb68d230b,0x9da070c8,0x84bb4189,
        0x03235d46,0x1a386c07,0x31153fc4,0x280e0e85,0x674f9842,0x7e54a903,0x5579fac0,0x4c62cb81,
        0x8138c51f,0x9823f45e,0xb30ea79d,0xaa1596dc,0xe554001b,0xfc4f315a,0xd7626299,0xce7953d8,
        0x49e14f17,0x50fa7e56,0x7bd72d95,0x62cc1cd4,0x2d8d8a13,0x3496bb52,0x1fbbe891,0x06a0d9d0,
        0x5e7ef3ec,0x4765c2ad,0x6c48916e,0x7553a02f,0x3a1236e8,0x230907a9,0x0824546a,0x113f652b,
        0x96a779e4,0x8fbc48a5,0xa4911b66,0xbd8a2a27,0xf2cbbce0,0xebd08da1,0xc0fdde62,0xd9e6ef23,
        0x14bce1bd,0x0da7d0fc,0x268a833f,0x3f91b27e,0x70d024b9,0x69cb15f8,0x42e6463b,0x5bfd777a,
        0xdc656bb5,0xc57e5af4,0xee530937,0xf7483876,0xb809aeb1,0xa1129ff0,0x8a3fcc33,0x9324fd72,
        
        0x00000000,0x01c26a37,0x0384d46e,0x0246be59,0x0709a8dc,0x06cbc2eb,0x048d7cb2,0x054f1685,
        0x0e1351b8,0x0fd13b8f,0x0d9785d6,0x0c55efe1,0x091af964,0x08d89353,0x0a9e2d0a,0x0b5c473d,
        0x1c26a370,0x1de4c947,0x1fa2771e,0x1e601d29,0x1b2f0bac,0x1aed619b,0x18abdfc2,0x1969b5f5,
        0x1235f2c8,0x13f798ff,0x11b126a6,0x10734c91,0x153c5a14,0x14fe3023,0x16b88e7a,0x177ae44d,
        0x384d46e0,0x398f2cd7,0x3bc9928e,0x3a0bf8b9,0x3f44ee3c,0x3e86840b,0x3cc03a52,0x3d025065,
        0x365e1758,0x379c7d6f,0x35dac336,0x3418a901,0x3157bf84,0x3095d5b3,0x32d36bea,0x331101dd,
        0x246be590,0x25a98fa7,0x27ef31fe,0x262d5bc9,0x23624d4c,0x22a0277b,0x20e69922,0x2124f315,
        0x2a78b428,0x2bbade1f,0x29fc6046,0x283e0a71,0x2d711cf4,0x2cb376c3,0x2ef5c89a,0x2f37a2ad,
        0x709a8dc0,0x7158e7f7,0x731e59ae,0x72dc3399,0x7793251c,0x76514f2b,0x7417f172,0x75d59b45,
        0x7e89dc78,0x7f4bb64f,0x7d0d0816,0x7ccf6221,0x798074a4,0x78421e93,0x7a04a0ca,0x7bc6cafd,
        0x6cbc2eb0,0x6d7e4487,0x6f38fade,0x6efa90e9,0x6bb5866c,0x6a77ec5b,0x68315202,0x69f33835,
        0x62af7f08,0x636d153f,0x612bab66,0x60e9c151,0x65a6d7d4,0x6464bde3,0x662203ba,0x67e0698d,
        0x48d7cb20,0x4915a117,0x4b531f4e,0x4a917579,0x4fde63fc,0x4e1c09cb,0x4c5ab792,0x4d98dda5,
        0x46c49a98,0x4706f0af,0x45404ef6,0x448224c1,0x41cd3244,0x400f5873,0x4249e62a,0x438b8c1d,
        0x54f16850,0x55330267,0x5775bc3e,0x56b7d609,0x53f8c08c,0x523aaabb,0x507c14e2,0x51be7ed5,
        0x5ae239e8,0x5b2053df,0x5966ed86,0x58a487b1,0x5deb9134,0x5c29fb03,0x5e6f455a,0x5fad2f6d,
        0xe1351b80,0xe0f771b7,0xe2b1cfee,0xe373a5d9,0xe63cb35c,0xe7fed96b,0xe5b86732,0xe47a0d05,
        0xef264a38,0xeee4200f,0xeca29e56,0xed60f461,0xe82fe2e4,0xe9ed88d3,0xebab368a,0xea695cbd,
        0xfd13b8f0,0xfcd1d2c7,0xfe976c9e,0xff5506a9,0xfa1a102c,0xfbd87a1b,0xf99ec442,0xf85cae75,
        0xf300e948,0xf2c2837f,0xf0843d26,0xf1465711,0xf4094194,0xf5cb2ba3,0xf78d95fa,0xf64fffcd,
        0xd9785d60,0xd8ba3757,0xdafc890e,0xdb3ee339,0xde71f5bc,0xdfb39f8b,0xddf521d2,0xdc374be5,
        0xd76b0cd8,0xd6a966ef,0xd4efd8b6,0xd52db281,0xd062a404,0xd1a0ce33,0xd3e6706a,0xd2241a5d,
        0xc55efe10,0xc49c9427,0xc6da2a7e,0xc7184049,0xc25756cc,0xc3953cfb,0xc1d382a2,0xc011e895,
        0xcb4dafa8,0xca8fc59f,0xc8c97bc6,0xc90b11f1,0xcc440774,0xcd866d43,0xcfc0d31a,0xce02b92d,
        0x91af9640,0x906dfc77,0x922b422e,0x93e92819,0x96a63e9c,0x976454ab,0x9522eaf2,0x94e080c5,
        0x9fbcc7f8,0x9e7eadcf,0x9c381396,0x9dfa79a1,0x98b56f24,0x99770513,0x9b31bb4a,0x9af3d17d,
        0x8d893530,0x8c4b5f07,0x8e0de15e,0x8fcf8b69,0x8a809dec,0x8b42f7db,0x89044982,0x88c623b5,
        0x839a6488,0x82580ebf,0x801eb0e6,0x81dcdad1,0x8493cc54,0x8551a663,0x8717183a,0x86d5720d,
        0xa9e2d0a0,0xa820ba97,0xaa6604ce,0xaba46ef9,0xaeeb787c,0xaf29124b,0xad6fac12,0xacadc625,
        0xa7f18118,0xa633eb2f,0xa4755576,0xa5b73f41,0xa0f829c4,0xa13a43f3,0xa37cfdaa,0xa2be979d,
        0xb5c473d0,0xb40619e7,0xb640a7be,0xb782cd89,0xb2cddb0c,0xb30fb13b,0xb1490f62,0xb08b6555,
        0xbbd72268,0xba15485f,0xb853f606,0xb9919c31,0xbcde8ab4,0xbd1ce083,0xbf5a5eda,0xbe9834ed,
        
        0x00000000,0xb8bc6765,0xaa09c88b,0x12b5afee,0x8f629757,0x37def032,0x256b5fdc,0x9dd738b9,
        0xc5b428ef,0x7d084f8a,0x6fbde064,0xd7018701,0x4ad6bfb8,0xf26ad8dd,0xe0df7733,0x58631056,
        0x5019579f,0xe8a530fa,0xfa109f14,0x42acf871,0xdf7bc0c8,0x67c7a7ad,0x75720843,0xcdce6f26,
        0x95ad7f70,0x2d111815,0x3fa4b7fb,0x8718d09e,0x1acfe827,0xa2738f42,0xb0c620ac,0x087a47c9,
        0xa032af3e,0x188ec85b,0x0a3b67b5,0xb28700d0,0x2f503869,0x97ec5f0c,0x8559f0e2,0x3de59787,
        0x658687d1,0xdd3ae0b4,0xcf8f4f5a,0x7733283f,0xeae41086,0x525877e3,0x40edd80d,0xf851bf68,
        0xf02bf8a1,0x48979fc4,0x5a22302a,0xe29e574f,0x7f496ff6,0xc7f50893,0xd540a77d,0x6dfcc018,
        0x359fd04e,0x8d23b72b,0x9f9618c5,0x272a7fa0,0xbafd4719,0x0241207c,0x10f48f92,0xa848e8f7,
        0x9b14583d,0x23a83f58,0x311d90b6,0x89a1f7d3,0x1476cf6a,0xaccaa80f,0xbe7f07e1,0x06c36084,
        0x5ea070d2,0xe61c17b7,0xf4a9b859,0x4c15df3c,0xd1c2e785,0x697e80e0,0x7bcb2f0e,0xc377486b,
        0xcb0d0fa2,0x73b168c7,0x6104c729,0xd9b8a04c,0x446f98f5,0xfcd3ff90,0xee66507e,0x56da371b,
        0x0eb9274d,0xb6054028,0xa4b0efc6,0x1c0c88a3,0x81dbb01a,0x3967d77f,0x2bd27891,0x936e1ff4,
        0x3b26f703,0x839a9066,0x912f3f88,0x299358ed,0xb4446054,0x0cf80731,0x1e4da8df,0xa6f1cfba,
        0xfe92dfec,0x462eb889,0x549b1767,0xec277002,0x71f048bb,0xc94c2fde,0xdbf98030,0x6345e755,
        0x6b3fa09c,0xd383c7f9,0xc1366817,0x798a0f72,0xe45d37cb,0x5ce150ae,0x4e54ff40,0xf6e89825,
        0xae8b8873,0x1637ef16,0x048240f8,0xbc3e279d,0x21e91f24,0x99557841,0x8be0d7af,0x335cb0ca,
        0xed59b63b,0x55e5d15e,0x47507eb0,0xffec19d5,0x623b216c,0xda874609,0xc832e9e7,0x708e8e82,
        0x28ed9ed4,0x9051f9b1,0x82e4565f,0x3a58313a,0xa78f0983,0x1f336ee6,0x0d86c108,0xb53aa66d,
        0xbd40e1a4,0x05fc86c1,0x1749292f,0xaff54e4a,0x322276f3,0x8a9e1196,0x982bbe78,0x2097d91d,
        0x78f4c94b,0xc048ae2e,0xd2fd01c0,0x6a4166a5,0xf7965e1c,0x4f2a3979,0x5d9f9697,0xe523f1f2,
        0x4d6b1905,0xf5d77e60,0xe762d18e,0x5fdeb6eb,0xc2098e52,0x7ab5e937,0x680046d9,0xd0bc21bc,
        0x88df31ea,0x3063568f,0x22d6f961,0x9a6a9e04,0x07bda6bd,0xbf01c1d8,0xadb46e36,0x15080953,
        0x1d724e9a,0xa5ce29ff,0xb77b8611,0x0fc7e174,0x9210d9cd,0x2aacbea8,0x38191146,0x80a57623,
        0xd8c66675,0x607a0110,0x72cfaefe,0xca73c99b,0x57a4f122,0xef189647,0xfdad39a9,0x45115ecc,
        0x764dee06,0xcef18963,0xdc44268d,0x64f841e8,0xf92f7951,0x41931e34,0x5326b1da,0xeb9ad6bf,
        0xb3f9c6e9,0x0b45a18c,0x19f00e62,0xa14c6907,0x3c9b51be,0x842736db,0x96929935,0x2e2efe50,
        0x2654b999,0x9ee8defc,0x8c5d7112,0x34e11677,0xa9362ece,0x118a49ab,0x033fe645,0xbb838120,
        0xe3e09176,0x5b5cf613,0x49e959fd,0xf1553e98,0x6c820621,0xd43e6144,0xc68bceaa,0x7e37a9cf,
        0xd67f4138,0x6ec3265d,0x7c7689b3,0xc4caeed6,0x591dd66f,0xe1a1b10a,0xf3141ee4,0x4ba87981,
        0x13cb69d7,0xab770eb2,0xb9c2a15c,0x017ec639,0x9ca9fe80,0x241599e5,0x36a0360b,0x8e1c516e,
        0x866616a7,0x3eda71c2,0x2c6fde2c,0x94d3b949,0x090481f0,0xb1b8e695,0xa30d497b,0x1bb12e1e,
        0x43d23e48,0xfb6e592d,0xe9dbf6c3,0x516791a6,0xccb0a91f,0x740cce7a,0x66b96194,0xde0506f1,
        
        0x00000000,0x3d6029b0,0x7ac05360,0x47a07ad0,0xf580a6c0,0xc8e08f70,0x8f40f5a0,0xb220dc10,
        0x30704bc1,0x0d106271,0x4ab018a1,0x77d03111,0xc5f0ed01,0xf890c4b1,0xbf30be61,0x825097d1,
        0x60e09782,0x5d80be32,0x1a20c4e2,0x2740ed52,0x95603142,0xa80018f2,0xefa06222,0xd2c04b92,
        0x5090dc43,0x6df0f5f3,0x2a508f23,0x1730a693,0xa5107a83,0x98705333,0xdfd029e3,0xe2b00053,
        0xc1c12f04,0xfca106b4,0xbb017c64,0x866155d4,0x344189c4,0x0921a074,0x4e81daa4,0x73e1f314,
        0xf1b164c5,0xccd14d75,0x8b7137a5,0xb6111e15,0x0431c205,0x3951ebb5,0x7ef19165,0x4391b8d5,
        0xa121b886,0x9c419136,0xdbe1ebe6,0xe681c256,0x54a11e46,0x69c137f6,0x2e614d26,0x13016496,
        0x9151f347,0xac31daf7,0xeb91a027,0xd6f18997,0x64d15587,0x59b17c37,0x1e1106e7,0x23712f57,
        0x58f35849,0x659371f9,0x22330b29,0x1f532299,0xad73fe89,0x9013d739,0xd7b3ade9,0xead38459,
        0x68831388,0x55e33a38,0x124340e8,0x2f236958,0x9d03b548,0xa0639cf8,0xe7c3e628,0xdaa3cf98,
        0x3813cfcb,0x0573e67b,0x42d39cab,0x7fb3b51b,0xcd93690b,0xf0f340bb,0xb7533a6b,0x8a3313db,
        0x0863840a,0x3503adba,0x72a3d76a,0x4fc3feda,0xfde322ca,0xc0830b7a,0x872371aa,0xba43581a,
        0x9932774d,0xa4525efd,0xe3f2242d,0xde920d9d,0x6cb2d18d,0x51d2f83d,0x167282ed,0x2b12ab5d,
        0xa9423c8c,0x9422153c,0xd3826fec,0xeee2465c,0x5cc29a4c,0x61a2b3fc,0x2602c92c,0x1b62e09c,
        0xf9d2e0cf,0xc4b2c97f,0x8312b3af,0xbe729a1f,0x0c52460f,0x31326fbf,0x7692156f,0x4bf23cdf,
        0xc9a2ab0e,0xf4c282be,0xb362f86e,0x8e02d1de,0x3c220dce,0x0142247e,0x46e25eae,0x7b82771e,
        0xb1e6b092,0x8c869922,0xcb26e3f2,0xf646ca42,0x44661652,0x79063fe2,0x3ea64532,0x03c66c82,
        0x8196fb53,0xbcf6d2e3,0xfb56a833,0xc6368183,0x74165d93,0x49767423,0x0ed60ef3,0x33b62743,
        0xd1062710,0xec660ea0,0xabc67470,0x96a65dc0,0x248681d0,0x19e6a860,0x5e46d2b0,0x6326fb00,
        0xe1766cd1,0xdc164561,0x9bb63fb1,0xa6d61601,0x14f6ca11,0x2996e3a1,0x6e369971,0x5356b0c1,
        0x70279f96,0x4d47b626,0x0ae7ccf6,0x3787e546,0x85a73956,0xb8c710e6,0xff676a36,0xc2074386,
        0x4057d457,0x7d37fde7,0x3a978737,0x07f7ae87,0xb5d77297,0x88b75b27,0xcf1721f7,0xf2770847,
        0x10c70814,0x2da721a4,0x6a075b74,0x576772c4,0xe547aed4,0xd8278764,0x9f87fdb4,0xa2e7d404,
        0x20b743d5,0x1dd76a65,0x5a7710b5,0x67173905,0xd537e515,0xe857cca5,0xaff7b675,0x92979fc5,
        0xe915e8db,0xd475c16b,0x93d5bbbb,0xaeb5920b,0x1c954e1b,0x21f567ab,0x66551d7b,0x5b3534cb,
        0xd965a31a,0xe4058aaa,0xa3a5f07a,0x9ec5d9ca,0x2ce505da,0x11852c6a,0x562556ba,0x6b457f0a,
        0x89f57f59,0xb49556e9,0xf3352c39,0xce550589,0x7c75d999,0x4115f029,0x06b58af9,0x3bd5a349,
        0xb9853498,0x84e51d28,0xc34567f8,0xfe254e48,0x4c059258,0x7165bbe8,0x36c5c138,0x0ba5e888,
        0x28d4c7df,0x15b4ee6f,0x521494bf,0x6f74bd0f,0xdd54611f,0xe03448af,0xa794327f,0x9af41bcf,
        0x18a48c1e,0x25c4a5ae,0x6264df7e,0x5f04f6ce,0xed242ade,0xd044036e,0x97e479be,0xaa84500e,
        0x4834505d,0x755479ed,0x32f4033d,0x0f942a8d,0xbdb4f69d,0x80d4df2d,0xc774a5fd,0xfa148c4d,
        0x78441b9c,0x4524322c,0x028448fc,0x3fe4614c,0x8dc4bd5c,0xb0a494ec,0xf704ee3c,0xca64c78c,
        
        0x00000000,0xcb5cd3a5,0x4dc8a10b,0x869472ae,0x9b914216,0x50cd91b3,0xd659e31d,0x1d0530b8,
        0xec53826d,0x270f51c8,0xa19b2366,0x6ac7f0c3,0x77c2c07b,0xbc9e13de,0x3a0a6170,0xf156b2d5,
        0x03d6029b,0xc88ad13e,0x4e1ea390,0x85427035,0x9847408d,0x531b9328,0xd58fe186,0x1ed33223,
        0xef8580f6,0x24d95353,0xa24d21fd,0x6911f258,0x7414c2e0,0xbf481145,0x39dc63eb,0xf280b04e,
        0x07ac0536,0xccf0d693,0x4a64a43d,0x81387798,0x9c3d4720,0x57619485,0xd1f5e62b,0x1aa9358e,
        0xebff875b,0x20a354fe,0xa6372650,0x6d6bf5f5,0x706ec54d,0xbb3216e8,0x3da66446,0xf6fab7e3,
        0x047a07ad,0xcf26d408,0x49b2a6a6,0x82ee7503,0x9feb45bb,0x54b7961e,0xd223e4b0,0x197f3715,
        0xe82985c0,0x23755665,0xa5e124cb,0x6ebdf76e,0x73b8c7d6,0xb8e41473,0x3e7066dd,0xf52cb578,
        0x0f580a6c,0xc404d9c9,0x4290ab67,0x89cc78c2,0x94c9487a,0x5f959bdf,0xd901e971,0x125d3ad4,
        0xe30b8801,0x28575ba4,0xaec3290a,0x659ffaaf,0x789aca17,0xb3c619b2,0x35526b1c,0xfe0eb8b9,
        0x0c8e08f7,0xc7d2db52,0x4146a9fc,0x8a1a7a59,0x971f4ae1,0x5c439944,0xdad7ebea,0x118b384f,
        0xe0dd8a9a,0x2b81593f,0xad152b91,0x6649f834,0x7b4cc88c,0xb0101b29,0x36846987,0xfdd8ba22,
        0x08f40f5a,0xc3a8dcff,0x453cae51,0x8e607df4,0x93654d4c,0x58399ee9,0xdeadec47,0x15f13fe2,
        0xe4a78d37,0x2ffb5e92,0xa96f2c3c,0x6233ff99,0x7f36cf21,0xb46a1c84,0x32fe6e2a,0xf9a2bd8f,
        0x0b220dc1,0xc07ede64,0x46eaacca,0x8db67f6f,0x90b34fd7,0x5bef9c72,0xdd7beedc,0x16273d79,
        0xe7718fac,0x2c2d5c09,0xaab92ea7,0x61e5fd02,0x7ce0cdba,0xb7bc1e1f,0x31286cb1,0xfa74bf14,
        0x1eb014d8,0xd5ecc77d,0x5378b5d3,0x98246676,0x852156ce,0x4e7d856b,0xc8e9f7c5,0x03b52460,
        0xf2e396b5,0x39bf4510,0xbf2b37be,0x7477e41b,0x6972d4a3,0xa22e0706,0x24ba75a8,0xefe6a60d,
        0x1d661643,0xd63ac5e6,0x50aeb748,0x9bf264ed,0x86f75455,0x4dab87f0,0xcb3ff55e,0x006326fb,
        0xf135942e,0x3a69478b,0xbcfd3525,0x77a1e680,0x6aa4d638,0xa1f8059d,0x276c7733,0xec30a496,
        0x191c11ee,0xd240c24b,0x54d4b0e5,0x9f886340,0x828d53f8,0x49d1805d,0xcf45f2f3,0x04192156,
        0xf54f9383,0x3e134026,0xb8873288,0x73dbe12d,0x6eded195,0xa5820230,0x2316709e,0xe84aa33b,
        0x1aca1375,0xd196c0d0,0x5702b27e,0x9c5e61db,0x815b5163,0x4a0782c6,0xcc93f068,0x07cf23cd,
        0xf6999118,0x3dc542bd,0xbb513013,0x700de3b6,0x6d08d30e,0xa65400ab,0x20c07205,0xeb9ca1a0,
        0x11e81eb4,0xdab4cd11,0x5c20bfbf,0x977c6c1a,0x8a795ca2,0x41258f07,0xc7b1fda9,0x0ced2e0c,
        0xfdbb9cd9,0x36e74f7c,0xb0733dd2,0x7b2fee77,0x662adecf,0xad760d6a,0x2be27fc4,0xe0beac61,
        0x123e1c2f,0xd962cf8a,0x5ff6bd24,0x94aa6e81,0x89af5e39,0x42f38d9c,0xc467ff32,0x0f3b2c97,
        0xfe6d9e42,0x35314de7,0xb3a53f49,0x78f9ecec,0x65fcdc54,0xaea00ff1,0x28347d5f,0xe368aefa,
        0x16441b82,0xdd18c827,0x5b8cba89,0x90d0692c,0x8dd55994,0x46898a31,0xc01df89f,0x0b412b3a,
        0xfa1799ef,0x314b4a4a,0xb7df38e4,0x7c83eb41,0x6186dbf9,0xaada085c,0x2c4e7af2,0xe712a957,
        0x15921919,0xdececabc,0x585ab812,0x93066bb7,0x8e035b0f,0x455f88aa,0xc3cbfa04,0x089729a1,
        0xf9c19b74,0x329d48d1,0xb4093a7f,0x7f55e9da,0x6250d962,0xa90c0ac7,0x2f987869,0xe4c4abcc,
        
        0x00000000,0xa6770bb4,0x979f1129,0x31e81a9d,0xf44f2413,0x52382fa7,0x63d0353a,0xc5a73e8e,
        0x33ef4e67,0x959845d3,0xa4705f4e,0x020754fa,0xc7a06a74,0x61d761c0,0x503f7b5d,0xf64870e9,
        0x67de9cce,0xc1a9977a,0xf0418de7,0x56368653,0x9391b8dd,0x35e6b369,0x040ea9f4,0xa279a240,
        0x5431d2a9,0xf246d91d,0xc3aec380,0x65d9c834,0xa07ef6ba,0x0609fd0e,0x37e1e793,0x9196ec27,
        0xcfbd399c,0x69ca3228,0x582228b5,0xfe552301,0x3bf21d8f,0x9d85163b,0xac6d0ca6,0x0a1a0712,
        0xfc5277fb,0x5a257c4f,0x6bcd66d2,0xcdba6d66,0x081d53e8,0xae6a585c,0x9f8242c1,0x39f54975,
        0xa863a552,0x0e14aee6,0x3ffcb47b,0x998bbfcf,0x5c2c8141,0xfa5b8af5,0xcbb39068,0x6dc49bdc,
        0x9b8ceb35,0x3dfbe081,0x0c13fa1c,0xaa64f1a8,0x6fc3cf26,0xc9b4c492,0xf85cde0f,0x5e2bd5bb,
        0x440b7579,0xe27c7ecd,0xd3946450,0x75e36fe4,0xb044516a,0x16335ade,0x27db4043,0x81ac4bf7,
        0x77e43b1e,0xd19330aa,0xe07b2a37,0x460c2183,0x83ab1f0d,0x25dc14b9,0x14340e24,0xb2430590,
        0x23d5e9b7,0x85a2e203,0xb44af89e,0x123df32a,0xd79acda4,0x71edc610,0x4005dc8d,0xe672d739,
        0x103aa7d0,0xb64dac64,0x87a5b6f9,0x21d2bd4d,0xe47583c3,0x42028877,0x73ea92ea,0xd59d995e,
        0x8bb64ce5,0x2dc14751,0x1c295dcc,0xba5e5678,0x7ff968f6,0xd98e6342,0xe86679df,0x4e11726b,
        0xb8590282,0x1e2e0936,0x2fc613ab,0x89b1181f,0x4c162691,0xea612d25,0xdb8937b8,0x7dfe3c0c,
        0xec68d02b,0x4a1fdb9f,0x7bf7c102,0xdd80cab6,0x1827f438,0xbe50ff8c,0x8fb8e511,0x29cfeea5,
        0xdf879e4c,0x79f095f8,0x48188f65,0xee6f84d1,0x2bc8ba5f,0x8dbfb1eb,0xbc57ab76,0x1a20a0c2,
        0x8816eaf2,0x2e61e146,0x1f89fbdb,0xb9fef06f,0x7c59cee1,0xda2ec555,0xebc6dfc8,0x4db1d47c,
        0xbbf9a495,0x1d8eaf21,0x2c66b5bc,0x8a11be08,0x4fb68086,0xe9c18b32,0xd82991af,0x7e5e9a1b,
        0xefc8763c,0x49bf7d88,0x78576715,0xde206ca1,0x1b87522f,0xbdf0599b,0x8c184306,0x2a6f48b2,
        0xdc27385b,0x7a5033ef,0x4bb82972,0xedcf22c6,0x28681c48,0x8e1f17fc,0xbff70d61,0x198006d5,
        0x47abd36e,0xe1dcd8da,0xd034c247,0x7643c9f3,0xb3e4f77d,0x1593fcc9,0x247be654,0x820cede0,
        0x74449d09,0xd23396bd,0xe3db8c20,0x45ac8794,0x800bb91a,0x267cb2ae,0x1794a833,0xb1e3a387,
        0x20754fa0,0x86024414,0xb7ea5e89,0x119d553d,0xd43a6bb3,0x724d6007,0x43a57a9a,0xe5d2712e,
        0x139a01c7,0xb5ed0a73,0x840510ee,0x22721b5a,0xe7d525d4,0x41a22e60,0x704a34fd,0xd63d3f49,
        0xcc1d9f8b,0x6a6a943f,0x5b828ea2,0xfdf58516,0x3852bb98,0x9e25b02c,0xafcdaab1,0x09baa105,
        0xfff2d1ec,0x5985da58,0x686dc0c5,0xce1acb71,0x0bbdf5ff,0xadcafe4b,0x9c22e4d6,0x3a55ef62,
        0xabc30345,0x0db408f1,0x3c5c126c,0x9a2b19d8,0x5f8c2756,0xf9fb2ce2,0xc813367f,0x6e643dcb,
        0x982c4d22,0x3e5b4696,0x0fb35c0b,0xa9c457bf,0x6c636931,0xca146285,0xfbfc7818,0x5d8b73ac,
        0x03a0a617,0xa5d7ada3,0x943fb73e,0x3248bc8a,0xf7ef8204,0x519889b0,0x6070932d,0xc6079899,
        0x304fe870,0x9638e3c4,0xa7d0f959,0x01a7f2ed,0xc400cc63,0x6277c7d7,0x539fdd4a,0xf5e8d6fe,
        0x647e3ad9,0xc209316d,0xf3e12bf0,0x55962044,0x90311eca,0x3646157e,0x07ae0fe3,0xa1d90457,
        0x579174be,0xf1e67f0a,0xc00e6597,0x66796e23,0xa3de50ad,0x05a95b19,0x34414184,0x92364a30,
        
        0x00000000,0xccaa009e,0x4225077d,0x8e8f07e3,0x844a0efa,0x48e00e64,0xc66f0987,0x0ac50919,
        0xd3e51bb5,0x1f4f1b2b,0x91c01cc8,0x5d6a1c56,0x57af154f,0x9b0515d1,0x158a1232,0xd92012ac,
        0x7cbb312b,0xb01131b5,0x3e9e3656,0xf23436c8,0xf8f13fd1,0x345b3f4f,0xbad438ac,0x767e3832,
        0xaf5e2a9e,0x63f42a00,0xed7b2de3,0x21d12d7d,0x2b142464,0xe7be24fa,0x69312319,0xa59b2387,
        0xf9766256,0x35dc62c8,0xbb53652b,0x77f965b5,0x7d3c6cac,0xb1966c32,0x3f196bd1,0xf3b36b4f,
        0x2a9379e3,0xe639797d,0x68b67e9e,0xa41c7e00,0xaed97719,0x62737787,0xecfc7064,0x205670fa,
        0x85cd537d,0x496753e3,0xc7e85400,0x0b42549e,0x01875d87,0xcd2d5d19,0x43a25afa,0x8f085a64,
        0x562848c8,0x9a824856,0x140d4fb5,0xd8a74f2b,0xd2624632,0x1ec846ac,0x9047414f,0x5ced41d1,
        0x299dc2ed,0xe537c273,0x6bb8c590,0xa712c50e,0xadd7cc17,0x617dcc89,0xeff2cb6a,0x2358cbf4,
        0xfa78d958,0x36d2d9c6,0xb85dde25,0x74f7debb,0x7e32d7a2,0xb298d73c,0x3c17d0df,0xf0bdd041,
        0x5526f3c6,0x998cf358,0x1703f4bb,0xdba9f425,0xd16cfd3c,0x1dc6fda2,0x9349fa41,0x5fe3fadf,
        0x86c3e873,0x4a69e8ed,0xc4e6ef0e,0x084cef90,0x0289e689,0xce23e617,0x40ace1f4,0x8c06e16a,
        0xd0eba0bb,0x1c41a025,0x92cea7c6,0x5e64a758,0x54a1ae41,0x980baedf,0x1684a93c,0xda2ea9a2,
        0x030ebb0e,0xcfa4bb90,0x412bbc73,0x8d81bced,0x8744b5f4,0x4beeb56a,0xc561b289,0x09cbb217,
        0xac509190,0x60fa910e,0xee7596ed,0x22df9673,0x281a9f6a,0xe4b09ff4,0x6a3f9817,0xa6959889,
        0x7fb58a25,0xb31f8abb,0x3d908d58,0xf13a8dc6,0xfbff84df,0x37558441,0xb9da83a2,0x7570833c,
        0x533b85da,0x9f918544,0x111e82a7,0xddb48239,0xd7718b20,0x1bdb8bbe,0x95548c5d,0x59fe8cc3,
        0x80de9e6f,0x4c749ef1,0xc2fb9912,0x0e51998c,0x04949095,0xc83e900b,0x46b197e8,0x8a1b9776,
        0x2f80b4f1,0xe32ab46f,0x6da5b38c,0xa10fb312,0xabcaba0b,0x6760ba95,0xe9efbd76,0x2545bde8,
        0xfc65af44,0x30cfafda,0xbe40a839,0x72eaa8a7,0x782fa1be,0xb485a120,0x3a0aa6c3,0xf6a0a65d,
        0xaa4de78c,0x66e7e712,0xe868e0f1,0x24c2e06f,0x2e07e976,0xe2ade9e8,0x6c22ee0b,0xa088ee95,
        0x79a8fc39,0xb502fca7,0x3b8dfb44,0xf727fbda,0xfde2f2c3,0x3148f25d,0xbfc7f5be,0x736df520,
        0xd6f6d6a7,0x1a5cd639,0x94d3d1da,0x5879d144,0x52bcd85d,0x9e16d8c3,0x1099df20,0xdc33dfbe,
        0x0513cd12,0xc9b9cd8c,0x4736ca6f,0x8b9ccaf1,0x8159c3e8,0x4df3c376,0xc37cc495,0x0fd6c40b,
        0x7aa64737,0xb60c47a9,0x3883404a,0xf42940d4,0xfeec49cd,0x32464953,0xbcc94eb0,0x70634e2e,
        0xa9435c82,0x65e95c1c,0xeb665bff,0x27cc5b61,0x2d095278,0xe1a352e6,0x6f2c5505,0xa386559b,
        0x061d761c,0xcab77682,0x44387161,0x889271ff,0x825778e6,0x4efd7878,0xc0727f9b,0x0cd87f05,
        0xd5f86da9,0x19526d37,0x97dd6ad4,0x5b776a4a,0x51b26353,0x9d1863cd,0x1397642e,0xdf3d64b0,
        0x83d02561,0x4f7a25ff,0xc1f5221c,0x0d5f2282,0x079a2b9b,0xcb302b05,0x45bf2ce6,0x89152c78,
        0x50353ed4,0x9c9f3e4a,0x121039a9,0xdeba3937,0xd47f302e,0x18d530b0,0x965a3753,0x5af037cd,
        0xff6b144a,0x33c114d4,0xbd4e1337,0x71e413a9,0x7b211ab0,0xb78b1a2e,0x39041dcd,0xf5ae1d53,
        0x2c8e0fff,0xe0240f61,0x6eab0882,0xa201081c,0xa8c40105,0x646e019b,0xeae10678,0x264b06e6,
    };

    inline u32 u8_crc32(u32 crc, u8 data)
    {
        crc = (crc >> 8) ^ g_crc32_table[(crc & 0xff) ^ data];
        return crc;
    }

#ifdef MANGO_CPU_64BIT

    // 64 bit crc32 (generic)

    inline u32 u64_crc32(u32 crc, const u8* ptr)
    {
        u64 data = *reinterpret_cast<const u64le *>(ptr);
        data = data ^ u64(crc);
        crc = g_crc32_table[((data>>56) & 0xff) + 0x000] ^
              g_crc32_table[((data>>48) & 0xff) + 0x100] ^
              g_crc32_table[((data>>40) & 0xff) + 0x200] ^
              g_crc32_table[((data>>32) & 0xff) + 0x300] ^
              g_crc32_table[((data>>24) & 0xff) + 0x400] ^
              g_crc32_table[((data>>16) & 0xff) + 0x500] ^
              g_crc32_table[((data>> 8) & 0xff) + 0x600] ^
              g_crc32_table[((data>> 0) & 0xff) + 0x700];
        return crc;
    }

#else

    // 32 bit crc32 (generic)

    inline u32 u64_crc32(u32 crc, const u8* ptr)
    {
        const u32le* p = reinterpret_cast<const u32le *>(ptr);
#ifdef MANGO_LITTLE_ENDIAN
        u32 one = p[0] ^ crc;
        u32 two = p[1];
#else
        u32 one = p[1] ^ crc;
        u32 two = p[0];
#endif
        crc = g_crc32_table[((two>>24) & 0xff) + 0x000] ^
              g_crc32_table[((two>>16) & 0xff) + 0x100] ^
              g_crc32_table[((two>> 8) & 0xff) + 0x200] ^
              g_crc32_table[((two>> 0) & 0xff) + 0x300] ^
              g_crc32_table[((one>>24) & 0xff) + 0x400] ^
              g_crc32_table[((one>>16) & 0xff) + 0x500] ^
              g_crc32_table[((one>> 8) & 0xff) + 0x600] ^
              g_crc32_table[((one>> 0) & 0xff) + 0x700];
        return crc;
    }

#endif // MANGO_CPU_64BIT
#endif // MANGO_HARDWARE_CRC32

#if !defined(MANGO_HARDWARE_CRC32C)
    
    constexpr u32 g_crc32c_table[] =
    {
        0x00000000,0xf26b8303,0xe13b70f7,0x1350f3f4,0xc79a971f,0x35f1141c,0x26a1e7e8,0xd4ca64eb,
        0x8ad958cf,0x78b2dbcc,0x6be22838,0x9989ab3b,0x4d43cfd0,0xbf284cd3,0xac78bf27,0x5e133c24,
        0x105ec76f,0xe235446c,0xf165b798,0x030e349b,0xd7c45070,0x25afd373,0x36ff2087,0xc494a384,
        0x9a879fa0,0x68ec1ca3,0x7bbcef57,0x89d76c54,0x5d1d08bf,0xaf768bbc,0xbc267848,0x4e4dfb4b,
        0x20bd8ede,0xd2d60ddd,0xc186fe29,0x33ed7d2a,0xe72719c1,0x154c9ac2,0x061c6936,0xf477ea35,
        0xaa64d611,0x580f5512,0x4b5fa6e6,0xb93425e5,0x6dfe410e,0x9f95c20d,0x8cc531f9,0x7eaeb2fa,
        0x30e349b1,0xc288cab2,0xd1d83946,0x23b3ba45,0xf779deae,0x05125dad,0x1642ae59,0xe4292d5a,
        0xba3a117e,0x4851927d,0x5b016189,0xa96ae28a,0x7da08661,0x8fcb0562,0x9c9bf696,0x6ef07595,
        0x417b1dbc,0xb3109ebf,0xa0406d4b,0x522bee48,0x86e18aa3,0x748a09a0,0x67dafa54,0x95b17957,
        0xcba24573,0x39c9c670,0x2a993584,0xd8f2b687,0x0c38d26c,0xfe53516f,0xed03a29b,0x1f682198,
        0x5125dad3,0xa34e59d0,0xb01eaa24,0x42752927,0x96bf4dcc,0x64d4cecf,0x77843d3b,0x85efbe38,
        0xdbfc821c,0x2997011f,0x3ac7f2eb,0xc8ac71e8,0x1c661503,0xee0d9600,0xfd5d65f4,0x0f36e6f7,
        0x61c69362,0x93ad1061,0x80fde395,0x72966096,0xa65c047d,0x5437877e,0x4767748a,0xb50cf789,
        0xeb1fcbad,0x197448ae,0x0a24bb5a,0xf84f3859,0x2c855cb2,0xdeeedfb1,0xcdbe2c45,0x3fd5af46,
        0x7198540d,0x83f3d70e,0x90a324fa,0x62c8a7f9,0xb602c312,0x44694011,0x5739b3e5,0xa55230e6,
        0xfb410cc2,0x092a8fc1,0x1a7a7c35,0xe811ff36,0x3cdb9bdd,0xceb018de,0xdde0eb2a,0x2f8b6829,
        0x82f63b78,0x709db87b,0x63cd4b8f,0x91a6c88c,0x456cac67,0xb7072f64,0xa457dc90,0x563c5f93,
        0x082f63b7,0xfa44e0b4,0xe9141340,0x1b7f9043,0xcfb5f4a8,0x3dde77ab,0x2e8e845f,0xdce5075c,
        0x92a8fc17,0x60c37f14,0x73938ce0,0x81f80fe3,0x55326b08,0xa759e80b,0xb4091bff,0x466298fc,
        0x1871a4d8,0xea1a27db,0xf94ad42f,0x0b21572c,0xdfeb33c7,0x2d80b0c4,0x3ed04330,0xccbbc033,
        0xa24bb5a6,0x502036a5,0x4370c551,0xb11b4652,0x65d122b9,0x97baa1ba,0x84ea524e,0x7681d14d,
        0x2892ed69,0xdaf96e6a,0xc9a99d9e,0x3bc21e9d,0xef087a76,0x1d63f975,0x0e330a81,0xfc588982,
        0xb21572c9,0x407ef1ca,0x532e023e,0xa145813d,0x758fe5d6,0x87e466d5,0x94b49521,0x66df1622,
        0x38cc2a06,0xcaa7a905,0xd9f75af1,0x2b9cd9f2,0xff56bd19,0x0d3d3e1a,0x1e6dcdee,0xec064eed,
        0xc38d26c4,0x31e6a5c7,0x22b65633,0xd0ddd530,0x0417b1db,0xf67c32d8,0xe52cc12c,0x1747422f,
        0x49547e0b,0xbb3ffd08,0xa86f0efc,0x5a048dff,0x8ecee914,0x7ca56a17,0x6ff599e3,0x9d9e1ae0,
        0xd3d3e1ab,0x21b862a8,0x32e8915c,0xc083125f,0x144976b4,0xe622f5b7,0xf5720643,0x07198540,
        0x590ab964,0xab613a67,0xb831c993,0x4a5a4a90,0x9e902e7b,0x6cfbad78,0x7fab5e8c,0x8dc0dd8f,
        0xe330a81a,0x115b2b19,0x020bd8ed,0xf0605bee,0x24aa3f05,0xd6c1bc06,0xc5914ff2,0x37faccf1,
        0x69e9f0d5,0x9b8273d6,0x88d28022,0x7ab90321,0xae7367ca,0x5c18e4c9,0x4f48173d,0xbd23943e,
        0xf36e6f75,0x0105ec76,0x12551f82,0xe03e9c81,0x34f4f86a,0xc69f7b69,0xd5cf889d,0x27a40b9e,
        0x79b737ba,0x8bdcb4b9,0x988c474d,0x6ae7c44e,0xbe2da0a5,0x4c4623a6,0x5f16d052,0xad7d5351,
        
        0x00000000,0x13a29877,0x274530ee,0x34e7a899,0x4e8a61dc,0x5d28f9ab,0x69cf5132,0x7a6dc945,
        0x9d14c3b8,0x8eb65bcf,0xba51f356,0xa9f36b21,0xd39ea264,0xc03c3a13,0xf4db928a,0xe7790afd,
        0x3fc5f181,0x2c6769f6,0x1880c16f,0x0b225918,0x714f905d,0x62ed082a,0x560aa0b3,0x45a838c4,
        0xa2d13239,0xb173aa4e,0x859402d7,0x96369aa0,0xec5b53e5,0xfff9cb92,0xcb1e630b,0xd8bcfb7c,
        0x7f8be302,0x6c297b75,0x58ced3ec,0x4b6c4b9b,0x310182de,0x22a31aa9,0x1644b230,0x05e62a47,
        0xe29f20ba,0xf13db8cd,0xc5da1054,0xd6788823,0xac154166,0xbfb7d911,0x8b507188,0x98f2e9ff,
        0x404e1283,0x53ec8af4,0x670b226d,0x74a9ba1a,0x0ec4735f,0x1d66eb28,0x298143b1,0x3a23dbc6,
        0xdd5ad13b,0xcef8494c,0xfa1fe1d5,0xe9bd79a2,0x93d0b0e7,0x80722890,0xb4958009,0xa737187e,
        0xff17c604,0xecb55e73,0xd852f6ea,0xcbf06e9d,0xb19da7d8,0xa23f3faf,0x96d89736,0x857a0f41,
        0x620305bc,0x71a19dcb,0x45463552,0x56e4ad25,0x2c896460,0x3f2bfc17,0x0bcc548e,0x186eccf9,
        0xc0d23785,0xd370aff2,0xe797076b,0xf4359f1c,0x8e585659,0x9dface2e,0xa91d66b7,0xbabffec0,
        0x5dc6f43d,0x4e646c4a,0x7a83c4d3,0x69215ca4,0x134c95e1,0x00ee0d96,0x3409a50f,0x27ab3d78,
        0x809c2506,0x933ebd71,0xa7d915e8,0xb47b8d9f,0xce1644da,0xddb4dcad,0xe9537434,0xfaf1ec43,
        0x1d88e6be,0x0e2a7ec9,0x3acdd650,0x296f4e27,0x53028762,0x40a01f15,0x7447b78c,0x67e52ffb,
        0xbf59d487,0xacfb4cf0,0x981ce469,0x8bbe7c1e,0xf1d3b55b,0xe2712d2c,0xd69685b5,0xc5341dc2,
        0x224d173f,0x31ef8f48,0x050827d1,0x16aabfa6,0x6cc776e3,0x7f65ee94,0x4b82460d,0x5820de7a,
        0xfbc3faf9,0xe861628e,0xdc86ca17,0xcf245260,0xb5499b25,0xa6eb0352,0x920cabcb,0x81ae33bc,
        0x66d73941,0x7575a136,0x419209af,0x523091d8,0x285d589d,0x3bffc0ea,0x0f186873,0x1cbaf004,
        0xc4060b78,0xd7a4930f,0xe3433b96,0xf0e1a3e1,0x8a8c6aa4,0x992ef2d3,0xadc95a4a,0xbe6bc23d,
        0x5912c8c0,0x4ab050b7,0x7e57f82e,0x6df56059,0x1798a91c,0x043a316b,0x30dd99f2,0x237f0185,
        0x844819fb,0x97ea818c,0xa30d2915,0xb0afb162,0xcac27827,0xd960e050,0xed8748c9,0xfe25d0be,
        0x195cda43,0x0afe4234,0x3e19eaad,0x2dbb72da,0x57d6bb9f,0x447423e8,0x70938b71,0x63311306,
        0xbb8de87a,0xa82f700d,0x9cc8d894,0x8f6a40e3,0xf50789a6,0xe6a511d1,0xd242b948,0xc1e0213f,
        0x26992bc2,0x353bb3b5,0x01dc1b2c,0x127e835b,0x68134a1e,0x7bb1d269,0x4f567af0,0x5cf4e287,
        0x04d43cfd,0x1776a48a,0x23910c13,0x30339464,0x4a5e5d21,0x59fcc556,0x6d1b6dcf,0x7eb9f5b8,
        0x99c0ff45,0x8a626732,0xbe85cfab,0xad2757dc,0xd74a9e99,0xc4e806ee,0xf00fae77,0xe3ad3600,
        0x3b11cd7c,0x28b3550b,0x1c54fd92,0x0ff665e5,0x759baca0,0x663934d7,0x52de9c4e,0x417c0439,
        0xa6050ec4,0xb5a796b3,0x81403e2a,0x92e2a65d,0xe88f6f18,0xfb2df76f,0xcfca5ff6,0xdc68c781,
        0x7b5fdfff,0x68fd4788,0x5c1aef11,0x4fb87766,0x35d5be23,0x26772654,0x12908ecd,0x013216ba,
        0xe64b1c47,0xf5e98430,0xc10e2ca9,0xd2acb4de,0xa8c17d9b,0xbb63e5ec,0x8f844d75,0x9c26d502,
        0x449a2e7e,0x5738b609,0x63df1e90,0x707d86e7,0x0a104fa2,0x19b2d7d5,0x2d557f4c,0x3ef7e73b,
        0xd98eedc6,0xca2c75b1,0xfecbdd28,0xed69455f,0x97048c1a,0x84a6146d,0xb041bcf4,0xa3e32483,
        
        0x00000000,0xa541927e,0x4f6f520d,0xea2ec073,0x9edea41a,0x3b9f3664,0xd1b1f617,0x74f06469,
        0x38513ec5,0x9d10acbb,0x773e6cc8,0xd27ffeb6,0xa68f9adf,0x03ce08a1,0xe9e0c8d2,0x4ca15aac,
        0x70a27d8a,0xd5e3eff4,0x3fcd2f87,0x9a8cbdf9,0xee7cd990,0x4b3d4bee,0xa1138b9d,0x045219e3,
        0x48f3434f,0xedb2d131,0x079c1142,0xa2dd833c,0xd62de755,0x736c752b,0x9942b558,0x3c032726,
        0xe144fb14,0x4405696a,0xae2ba919,0x0b6a3b67,0x7f9a5f0e,0xdadbcd70,0x30f50d03,0x95b49f7d,
        0xd915c5d1,0x7c5457af,0x967a97dc,0x333b05a2,0x47cb61cb,0xe28af3b5,0x08a433c6,0xade5a1b8,
        0x91e6869e,0x34a714e0,0xde89d493,0x7bc846ed,0x0f382284,0xaa79b0fa,0x40577089,0xe516e2f7,
        0xa9b7b85b,0x0cf62a25,0xe6d8ea56,0x43997828,0x37691c41,0x92288e3f,0x78064e4c,0xdd47dc32,
        0xc76580d9,0x622412a7,0x880ad2d4,0x2d4b40aa,0x59bb24c3,0xfcfab6bd,0x16d476ce,0xb395e4b0,
        0xff34be1c,0x5a752c62,0xb05bec11,0x151a7e6f,0x61ea1a06,0xc4ab8878,0x2e85480b,0x8bc4da75,
        0xb7c7fd53,0x12866f2d,0xf8a8af5e,0x5de93d20,0x29195949,0x8c58cb37,0x66760b44,0xc337993a,
        0x8f96c396,0x2ad751e8,0xc0f9919b,0x65b803e5,0x1148678c,0xb409f5f2,0x5e273581,0xfb66a7ff,
        0x26217bcd,0x8360e9b3,0x694e29c0,0xcc0fbbbe,0xb8ffdfd7,0x1dbe4da9,0xf7908dda,0x52d11fa4,
        0x1e704508,0xbb31d776,0x511f1705,0xf45e857b,0x80aee112,0x25ef736c,0xcfc1b31f,0x6a802161,
        0x56830647,0xf3c29439,0x19ec544a,0xbcadc634,0xc85da25d,0x6d1c3023,0x8732f050,0x2273622e,
        0x6ed23882,0xcb93aafc,0x21bd6a8f,0x84fcf8f1,0xf00c9c98,0x554d0ee6,0xbf63ce95,0x1a225ceb,
        0x8b277743,0x2e66e53d,0xc448254e,0x6109b730,0x15f9d359,0xb0b84127,0x5a968154,0xffd7132a,
        0xb3764986,0x1637dbf8,0xfc191b8b,0x595889f5,0x2da8ed9c,0x88e97fe2,0x62c7bf91,0xc7862def,
        0xfb850ac9,0x5ec498b7,0xb4ea58c4,0x11abcaba,0x655baed3,0xc01a3cad,0x2a34fcde,0x8f756ea0,
        0xc3d4340c,0x6695a672,0x8cbb6601,0x29faf47f,0x5d0a9016,0xf84b0268,0x1265c21b,0xb7245065,
        0x6a638c57,0xcf221e29,0x250cde5a,0x804d4c24,0xf4bd284d,0x51fcba33,0xbbd27a40,0x1e93e83e,
        0x5232b292,0xf77320ec,0x1d5de09f,0xb81c72e1,0xccec1688,0x69ad84f6,0x83834485,0x26c2d6fb,
        0x1ac1f1dd,0xbf8063a3,0x55aea3d0,0xf0ef31ae,0x841f55c7,0x215ec7b9,0xcb7007ca,0x6e3195b4,
        0x2290cf18,0x87d15d66,0x6dff9d15,0xc8be0f6b,0xbc4e6b02,0x190ff97c,0xf321390f,0x5660ab71,
        0x4c42f79a,0xe90365e4,0x032da597,0xa66c37e9,0xd29c5380,0x77ddc1fe,0x9df3018d,0x38b293f3,
        0x7413c95f,0xd1525b21,0x3b7c9b52,0x9e3d092c,0xeacd6d45,0x4f8cff3b,0xa5a23f48,0x00e3ad36,
        0x3ce08a10,0x99a1186e,0x738fd81d,0xd6ce4a63,0xa23e2e0a,0x077fbc74,0xed517c07,0x4810ee79,
        0x04b1b4d5,0xa1f026ab,0x4bdee6d8,0xee9f74a6,0x9a6f10cf,0x3f2e82b1,0xd50042c2,0x7041d0bc,
        0xad060c8e,0x08479ef0,0xe2695e83,0x4728ccfd,0x33d8a894,0x96993aea,0x7cb7fa99,0xd9f668e7,
        0x9557324b,0x3016a035,0xda386046,0x7f79f238,0x0b899651,0xaec8042f,0x44e6c45c,0xe1a75622,
        0xdda47104,0x78e5e37a,0x92cb2309,0x378ab177,0x437ad51e,0xe63b4760,0x0c158713,0xa954156d,
        0xe5f54fc1,0x40b4ddbf,0xaa9a1dcc,0x0fdb8fb2,0x7b2bebdb,0xde6a79a5,0x3444b9d6,0x91052ba8,
        
        0x00000000,0xdd45aab8,0xbf672381,0x62228939,0x7b2231f3,0xa6679b4b,0xc4451272,0x1900b8ca,
        0xf64463e6,0x2b01c95e,0x49234067,0x9466eadf,0x8d665215,0x5023f8ad,0x32017194,0xef44db2c,
        0xe964b13d,0x34211b85,0x560392bc,0x8b463804,0x924680ce,0x4f032a76,0x2d21a34f,0xf06409f7,
        0x1f20d2db,0xc2657863,0xa047f15a,0x7d025be2,0x6402e328,0xb9474990,0xdb65c0a9,0x06206a11,
        0xd725148b,0x0a60be33,0x6842370a,0xb5079db2,0xac072578,0x71428fc0,0x136006f9,0xce25ac41,
        0x2161776d,0xfc24ddd5,0x9e0654ec,0x4343fe54,0x5a43469e,0x8706ec26,0xe524651f,0x3861cfa7,
        0x3e41a5b6,0xe3040f0e,0x81268637,0x5c632c8f,0x45639445,0x98263efd,0xfa04b7c4,0x27411d7c,
        0xc805c650,0x15406ce8,0x7762e5d1,0xaa274f69,0xb327f7a3,0x6e625d1b,0x0c40d422,0xd1057e9a,
        0xaba65fe7,0x76e3f55f,0x14c17c66,0xc984d6de,0xd0846e14,0x0dc1c4ac,0x6fe34d95,0xb2a6e72d,
        0x5de23c01,0x80a796b9,0xe2851f80,0x3fc0b538,0x26c00df2,0xfb85a74a,0x99a72e73,0x44e284cb,
        0x42c2eeda,0x9f874462,0xfda5cd5b,0x20e067e3,0x39e0df29,0xe4a57591,0x8687fca8,0x5bc25610,
        0xb4868d3c,0x69c32784,0x0be1aebd,0xd6a40405,0xcfa4bccf,0x12e11677,0x70c39f4e,0xad8635f6,
        0x7c834b6c,0xa1c6e1d4,0xc3e468ed,0x1ea1c255,0x07a17a9f,0xdae4d027,0xb8c6591e,0x6583f3a6,
        0x8ac7288a,0x57828232,0x35a00b0b,0xe8e5a1b3,0xf1e51979,0x2ca0b3c1,0x4e823af8,0x93c79040,
        0x95e7fa51,0x48a250e9,0x2a80d9d0,0xf7c57368,0xeec5cba2,0x3380611a,0x51a2e823,0x8ce7429b,
        0x63a399b7,0xbee6330f,0xdcc4ba36,0x0181108e,0x1881a844,0xc5c402fc,0xa7e68bc5,0x7aa3217d,
        0x52a0c93f,0x8fe56387,0xedc7eabe,0x30824006,0x2982f8cc,0xf4c75274,0x96e5db4d,0x4ba071f5,
        0xa4e4aad9,0x79a10061,0x1b838958,0xc6c623e0,0xdfc69b2a,0x02833192,0x60a1b8ab,0xbde41213,
        0xbbc47802,0x6681d2ba,0x04a35b83,0xd9e6f13b,0xc0e649f1,0x1da3e349,0x7f816a70,0xa2c4c0c8,
        0x4d801be4,0x90c5b15c,0xf2e73865,0x2fa292dd,0x36a22a17,0xebe780af,0x89c50996,0x5480a32e,
        0x8585ddb4,0x58c0770c,0x3ae2fe35,0xe7a7548d,0xfea7ec47,0x23e246ff,0x41c0cfc6,0x9c85657e,
        0x73c1be52,0xae8414ea,0xcca69dd3,0x11e3376b,0x08e38fa1,0xd5a62519,0xb784ac20,0x6ac10698,
        0x6ce16c89,0xb1a4c631,0xd3864f08,0x0ec3e5b0,0x17c35d7a,0xca86f7c2,0xa8a47efb,0x75e1d443,
        0x9aa50f6f,0x47e0a5d7,0x25c22cee,0xf8878656,0xe1873e9c,0x3cc29424,0x5ee01d1d,0x83a5b7a5,
        0xf90696d8,0x24433c60,0x4661b559,0x9b241fe1,0x8224a72b,0x5f610d93,0x3d4384aa,0xe0062e12,
        0x0f42f53e,0xd2075f86,0xb025d6bf,0x6d607c07,0x7460c4cd,0xa9256e75,0xcb07e74c,0x16424df4,
        0x106227e5,0xcd278d5d,0xaf050464,0x7240aedc,0x6b401616,0xb605bcae,0xd4273597,0x09629f2f,
        0xe6264403,0x3b63eebb,0x59416782,0x8404cd3a,0x9d0475f0,0x4041df48,0x22635671,0xff26fcc9,
        0x2e238253,0xf36628eb,0x9144a1d2,0x4c010b6a,0x5501b3a0,0x88441918,0xea669021,0x37233a99,
        0xd867e1b5,0x05224b0d,0x6700c234,0xba45688c,0xa345d046,0x7e007afe,0x1c22f3c7,0xc167597f,
        0xc747336e,0x1a0299d6,0x782010ef,0xa565ba57,0xbc65029d,0x6120a825,0x0302211c,0xde478ba4,
        0x31035088,0xec46fa30,0x8e647309,0x5321d9b1,0x4a21617b,0x9764cbc3,0xf54642fa,0x2803e842,
        
        0x00000000,0x38116fac,0x7022df58,0x4833b0f4,0xe045beb0,0xd854d11c,0x906761e8,0xa8760e44,
        0xc5670b91,0xfd76643d,0xb545d4c9,0x8d54bb65,0x2522b521,0x1d33da8d,0x55006a79,0x6d1105d5,
        0x8f2261d3,0xb7330e7f,0xff00be8b,0xc711d127,0x6f67df63,0x5776b0cf,0x1f45003b,0x27546f97,
        0x4a456a42,0x725405ee,0x3a67b51a,0x0276dab6,0xaa00d4f2,0x9211bb5e,0xda220baa,0xe2336406,
        0x1ba8b557,0x23b9dafb,0x6b8a6a0f,0x539b05a3,0xfbed0be7,0xc3fc644b,0x8bcfd4bf,0xb3debb13,
        0xdecfbec6,0xe6ded16a,0xaeed619e,0x96fc0e32,0x3e8a0076,0x069b6fda,0x4ea8df2e,0x76b9b082,
        0x948ad484,0xac9bbb28,0xe4a80bdc,0xdcb96470,0x74cf6a34,0x4cde0598,0x04edb56c,0x3cfcdac0,
        0x51eddf15,0x69fcb0b9,0x21cf004d,0x19de6fe1,0xb1a861a5,0x89b90e09,0xc18abefd,0xf99bd151,
        0x37516aae,0x0f400502,0x4773b5f6,0x7f62da5a,0xd714d41e,0xef05bbb2,0xa7360b46,0x9f2764ea,
        0xf236613f,0xca270e93,0x8214be67,0xba05d1cb,0x1273df8f,0x2a62b023,0x625100d7,0x5a406f7b,
        0xb8730b7d,0x806264d1,0xc851d425,0xf040bb89,0x5836b5cd,0x6027da61,0x28146a95,0x10050539,
        0x7d1400ec,0x45056f40,0x0d36dfb4,0x3527b018,0x9d51be5c,0xa540d1f0,0xed736104,0xd5620ea8,
        0x2cf9dff9,0x14e8b055,0x5cdb00a1,0x64ca6f0d,0xccbc6149,0xf4ad0ee5,0xbc9ebe11,0x848fd1bd,
        0xe99ed468,0xd18fbbc4,0x99bc0b30,0xa1ad649c,0x09db6ad8,0x31ca0574,0x79f9b580,0x41e8da2c,
        0xa3dbbe2a,0x9bcad186,0xd3f96172,0xebe80ede,0x439e009a,0x7b8f6f36,0x33bcdfc2,0x0badb06e,
        0x66bcb5bb,0x5eadda17,0x169e6ae3,0x2e8f054f,0x86f90b0b,0xbee864a7,0xf6dbd453,0xcecabbff,
        0x6ea2d55c,0x56b3baf0,0x1e800a04,0x269165a8,0x8ee76bec,0xb6f60440,0xfec5b4b4,0xc6d4db18,
        0xabc5decd,0x93d4b161,0xdbe70195,0xe3f66e39,0x4b80607d,0x73910fd1,0x3ba2bf25,0x03b3d089,
        0xe180b48f,0xd991db23,0x91a26bd7,0xa9b3047b,0x01c50a3f,0x39d46593,0x71e7d567,0x49f6bacb,
        0x24e7bf1e,0x1cf6d0b2,0x54c56046,0x6cd40fea,0xc4a201ae,0xfcb36e02,0xb480def6,0x8c91b15a,
        0x750a600b,0x4d1b0fa7,0x0528bf53,0x3d39d0ff,0x954fdebb,0xad5eb117,0xe56d01e3,0xdd7c6e4f,
        0xb06d6b9a,0x887c0436,0xc04fb4c2,0xf85edb6e,0x5028d52a,0x6839ba86,0x200a0a72,0x181b65de,
        0xfa2801d8,0xc2396e74,0x8a0ade80,0xb21bb12c,0x1a6dbf68,0x227cd0c4,0x6a4f6030,0x525e0f9c,
        0x3f4f0a49,0x075e65e5,0x4f6dd511,0x777cbabd,0xdf0ab4f9,0xe71bdb55,0xaf286ba1,0x9739040d,
        0x59f3bff2,0x61e2d05e,0x29d160aa,0x11c00f06,0xb9b60142,0x81a76eee,0xc994de1a,0xf185b1b6,
        0x9c94b463,0xa485dbcf,0xecb66b3b,0xd4a70497,0x7cd10ad3,0x44c0657f,0x0cf3d58b,0x34e2ba27,
        0xd6d1de21,0xeec0b18d,0xa6f30179,0x9ee26ed5,0x36946091,0x0e850f3d,0x46b6bfc9,0x7ea7d065,
        0x13b6d5b0,0x2ba7ba1c,0x63940ae8,0x5b856544,0xf3f36b00,0xcbe204ac,0x83d1b458,0xbbc0dbf4,
        0x425b0aa5,0x7a4a6509,0x3279d5fd,0x0a68ba51,0xa21eb415,0x9a0fdbb9,0xd23c6b4d,0xea2d04e1,
        0x873c0134,0xbf2d6e98,0xf71ede6c,0xcf0fb1c0,0x6779bf84,0x5f68d028,0x175b60dc,0x2f4a0f70,
        0xcd796b76,0xf56804da,0xbd5bb42e,0x854adb82,0x2d3cd5c6,0x152dba6a,0x5d1e0a9e,0x650f6532,
        0x081e60e7,0x300f0f4b,0x783cbfbf,0x402dd013,0xe85bde57,0xd04ab1fb,0x9879010f,0xa0686ea3,
        
        0x00000000,0xef306b19,0xdb8ca0c3,0x34bccbda,0xb2f53777,0x5dc55c6e,0x697997b4,0x8649fcad,
        0x6006181f,0x8f367306,0xbb8ab8dc,0x54bad3c5,0xd2f32f68,0x3dc34471,0x097f8fab,0xe64fe4b2,
        0xc00c303e,0x2f3c5b27,0x1b8090fd,0xf4b0fbe4,0x72f90749,0x9dc96c50,0xa975a78a,0x4645cc93,
        0xa00a2821,0x4f3a4338,0x7b8688e2,0x94b6e3fb,0x12ff1f56,0xfdcf744f,0xc973bf95,0x2643d48c,
        0x85f4168d,0x6ac47d94,0x5e78b64e,0xb148dd57,0x370121fa,0xd8314ae3,0xec8d8139,0x03bdea20,
        0xe5f20e92,0x0ac2658b,0x3e7eae51,0xd14ec548,0x570739e5,0xb83752fc,0x8c8b9926,0x63bbf23f,
        0x45f826b3,0xaac84daa,0x9e748670,0x7144ed69,0xf70d11c4,0x183d7add,0x2c81b107,0xc3b1da1e,
        0x25fe3eac,0xcace55b5,0xfe729e6f,0x1142f576,0x970b09db,0x783b62c2,0x4c87a918,0xa3b7c201,
        0x0e045beb,0xe13430f2,0xd588fb28,0x3ab89031,0xbcf16c9c,0x53c10785,0x677dcc5f,0x884da746,
        0x6e0243f4,0x813228ed,0xb58ee337,0x5abe882e,0xdcf77483,0x33c71f9a,0x077bd440,0xe84bbf59,
        0xce086bd5,0x213800cc,0x1584cb16,0xfab4a00f,0x7cfd5ca2,0x93cd37bb,0xa771fc61,0x48419778,
        0xae0e73ca,0x413e18d3,0x7582d309,0x9ab2b810,0x1cfb44bd,0xf3cb2fa4,0xc777e47e,0x28478f67,
        0x8bf04d66,0x64c0267f,0x507ceda5,0xbf4c86bc,0x39057a11,0xd6351108,0xe289dad2,0x0db9b1cb,
        0xebf65579,0x04c63e60,0x307af5ba,0xdf4a9ea3,0x5903620e,0xb6330917,0x828fc2cd,0x6dbfa9d4,
        0x4bfc7d58,0xa4cc1641,0x9070dd9b,0x7f40b682,0xf9094a2f,0x16392136,0x2285eaec,0xcdb581f5,
        0x2bfa6547,0xc4ca0e5e,0xf076c584,0x1f46ae9d,0x990f5230,0x763f3929,0x4283f2f3,0xadb399ea,
        0x1c08b7d6,0xf338dccf,0xc7841715,0x28b47c0c,0xaefd80a1,0x41cdebb8,0x75712062,0x9a414b7b,
        0x7c0eafc9,0x933ec4d0,0xa7820f0a,0x48b26413,0xcefb98be,0x21cbf3a7,0x1577387d,0xfa475364,
        0xdc0487e8,0x3334ecf1,0x0788272b,0xe8b84c32,0x6ef1b09f,0x81c1db86,0xb57d105c,0x5a4d7b45,
        0xbc029ff7,0x5332f4ee,0x678e3f34,0x88be542d,0x0ef7a880,0xe1c7c399,0xd57b0843,0x3a4b635a,
        0x99fca15b,0x76ccca42,0x42700198,0xad406a81,0x2b09962c,0xc439fd35,0xf08536ef,0x1fb55df6,
        0xf9fab944,0x16cad25d,0x22761987,0xcd46729e,0x4b0f8e33,0xa43fe52a,0x90832ef0,0x7fb345e9,
        0x59f09165,0xb6c0fa7c,0x827c31a6,0x6d4c5abf,0xeb05a612,0x0435cd0b,0x308906d1,0xdfb96dc8,
        0x39f6897a,0xd6c6e263,0xe27a29b9,0x0d4a42a0,0x8b03be0d,0x6433d514,0x508f1ece,0xbfbf75d7,
        0x120cec3d,0xfd3c8724,0xc9804cfe,0x26b027e7,0xa0f9db4a,0x4fc9b053,0x7b757b89,0x94451090,
        0x720af422,0x9d3a9f3b,0xa98654e1,0x46b63ff8,0xc0ffc355,0x2fcfa84c,0x1b736396,0xf443088f,
        0xd200dc03,0x3d30b71a,0x098c7cc0,0xe6bc17d9,0x60f5eb74,0x8fc5806d,0xbb794bb7,0x544920ae,
        0xb206c41c,0x5d36af05,0x698a64df,0x86ba0fc6,0x00f3f36b,0xefc39872,0xdb7f53a8,0x344f38b1,
        0x97f8fab0,0x78c891a9,0x4c745a73,0xa344316a,0x250dcdc7,0xca3da6de,0xfe816d04,0x11b1061d,
        0xf7fee2af,0x18ce89b6,0x2c72426c,0xc3422975,0x450bd5d8,0xaa3bbec1,0x9e87751b,0x71b71e02,
        0x57f4ca8e,0xb8c4a197,0x8c786a4d,0x63480154,0xe501fdf9,0x0a3196e0,0x3e8d5d3a,0xd1bd3623,
        0x37f2d291,0xd8c2b988,0xec7e7252,0x034e194b,0x8507e5e6,0x6a378eff,0x5e8b4525,0xb1bb2e3c,
        
        0x00000000,0x68032cc8,0xd0065990,0xb8057558,0xa5e0c5d1,0xcde3e919,0x75e69c41,0x1de5b089,
        0x4e2dfd53,0x262ed19b,0x9e2ba4c3,0xf628880b,0xebcd3882,0x83ce144a,0x3bcb6112,0x53c84dda,
        0x9c5bfaa6,0xf458d66e,0x4c5da336,0x245e8ffe,0x39bb3f77,0x51b813bf,0xe9bd66e7,0x81be4a2f,
        0xd27607f5,0xba752b3d,0x02705e65,0x6a7372ad,0x7796c224,0x1f95eeec,0xa7909bb4,0xcf93b77c,
        0x3d5b83bd,0x5558af75,0xed5dda2d,0x855ef6e5,0x98bb466c,0xf0b86aa4,0x48bd1ffc,0x20be3334,
        0x73767eee,0x1b755226,0xa370277e,0xcb730bb6,0xd696bb3f,0xbe9597f7,0x0690e2af,0x6e93ce67,
        0xa100791b,0xc90355d3,0x7106208b,0x19050c43,0x04e0bcca,0x6ce39002,0xd4e6e55a,0xbce5c992,
        0xef2d8448,0x872ea880,0x3f2bddd8,0x5728f110,0x4acd4199,0x22ce6d51,0x9acb1809,0xf2c834c1,
        0x7ab7077a,0x12b42bb2,0xaab15eea,0xc2b27222,0xdf57c2ab,0xb754ee63,0x0f519b3b,0x6752b7f3,
        0x349afa29,0x5c99d6e1,0xe49ca3b9,0x8c9f8f71,0x917a3ff8,0xf9791330,0x417c6668,0x297f4aa0,
        0xe6ecfddc,0x8eefd114,0x36eaa44c,0x5ee98884,0x430c380d,0x2b0f14c5,0x930a619d,0xfb094d55,
        0xa8c1008f,0xc0c22c47,0x78c7591f,0x10c475d7,0x0d21c55e,0x6522e996,0xdd279cce,0xb524b006,
        0x47ec84c7,0x2fefa80f,0x97eadd57,0xffe9f19f,0xe20c4116,0x8a0f6dde,0x320a1886,0x5a09344e,
        0x09c17994,0x61c2555c,0xd9c72004,0xb1c40ccc,0xac21bc45,0xc422908d,0x7c27e5d5,0x1424c91d,
        0xdbb77e61,0xb3b452a9,0x0bb127f1,0x63b20b39,0x7e57bbb0,0x16549778,0xae51e220,0xc652cee8,
        0x959a8332,0xfd99affa,0x459cdaa2,0x2d9ff66a,0x307a46e3,0x58796a2b,0xe07c1f73,0x887f33bb,
        0xf56e0ef4,0x9d6d223c,0x25685764,0x4d6b7bac,0x508ecb25,0x388de7ed,0x808892b5,0xe88bbe7d,
        0xbb43f3a7,0xd340df6f,0x6b45aa37,0x034686ff,0x1ea33676,0x76a01abe,0xcea56fe6,0xa6a6432e,
        0x6935f452,0x0136d89a,0xb933adc2,0xd130810a,0xccd53183,0xa4d61d4b,0x1cd36813,0x74d044db,
        0x27180901,0x4f1b25c9,0xf71e5091,0x9f1d7c59,0x82f8ccd0,0xeafbe018,0x52fe9540,0x3afdb988,
        0xc8358d49,0xa036a181,0x1833d4d9,0x7030f811,0x6dd54898,0x05d66450,0xbdd31108,0xd5d03dc0,
        0x8618701a,0xee1b5cd2,0x561e298a,0x3e1d0542,0x23f8b5cb,0x4bfb9903,0xf3feec5b,0x9bfdc093,
        0x546e77ef,0x3c6d5b27,0x84682e7f,0xec6b02b7,0xf18eb23e,0x998d9ef6,0x2188ebae,0x498bc766,
        0x1a438abc,0x7240a674,0xca45d32c,0xa246ffe4,0xbfa34f6d,0xd7a063a5,0x6fa516fd,0x07a63a35,
        0x8fd9098e,0xe7da2546,0x5fdf501e,0x37dc7cd6,0x2a39cc5f,0x423ae097,0xfa3f95cf,0x923cb907,
        0xc1f4f4dd,0xa9f7d815,0x11f2ad4d,0x79f18185,0x6414310c,0x0c171dc4,0xb412689c,0xdc114454,
        0x1382f328,0x7b81dfe0,0xc384aab8,0xab878670,0xb66236f9,0xde611a31,0x66646f69,0x0e6743a1,
        0x5daf0e7b,0x35ac22b3,0x8da957eb,0xe5aa7b23,0xf84fcbaa,0x904ce762,0x2849923a,0x404abef2,
        0xb2828a33,0xda81a6fb,0x6284d3a3,0x0a87ff6b,0x17624fe2,0x7f61632a,0xc7641672,0xaf673aba,
        0xfcaf7760,0x94ac5ba8,0x2ca92ef0,0x44aa0238,0x594fb2b1,0x314c9e79,0x8949eb21,0xe14ac7e9,
        0x2ed97095,0x46da5c5d,0xfedf2905,0x96dc05cd,0x8b39b544,0xe33a998c,0x5b3fecd4,0x333cc01c,
        0x60f48dc6,0x08f7a10e,0xb0f2d456,0xd8f1f89e,0xc5144817,0xad1764df,0x15121187,0x7d113d4f,
        
        0x00000000,0x493c7d27,0x9278fa4e,0xdb448769,0x211d826d,0x6821ff4a,0xb3657823,0xfa590504,
        0x423b04da,0x0b0779fd,0xd043fe94,0x997f83b3,0x632686b7,0x2a1afb90,0xf15e7cf9,0xb86201de,
        0x847609b4,0xcd4a7493,0x160ef3fa,0x5f328edd,0xa56b8bd9,0xec57f6fe,0x37137197,0x7e2f0cb0,
        0xc64d0d6e,0x8f717049,0x5435f720,0x1d098a07,0xe7508f03,0xae6cf224,0x7528754d,0x3c14086a,
        0x0d006599,0x443c18be,0x9f789fd7,0xd644e2f0,0x2c1de7f4,0x65219ad3,0xbe651dba,0xf759609d,
        0x4f3b6143,0x06071c64,0xdd439b0d,0x947fe62a,0x6e26e32e,0x271a9e09,0xfc5e1960,0xb5626447,
        0x89766c2d,0xc04a110a,0x1b0e9663,0x5232eb44,0xa86bee40,0xe1579367,0x3a13140e,0x732f6929,
        0xcb4d68f7,0x827115d0,0x593592b9,0x1009ef9e,0xea50ea9a,0xa36c97bd,0x782810d4,0x31146df3,
        0x1a00cb32,0x533cb615,0x8878317c,0xc1444c5b,0x3b1d495f,0x72213478,0xa965b311,0xe059ce36,
        0x583bcfe8,0x1107b2cf,0xca4335a6,0x837f4881,0x79264d85,0x301a30a2,0xeb5eb7cb,0xa262caec,
        0x9e76c286,0xd74abfa1,0x0c0e38c8,0x453245ef,0xbf6b40eb,0xf6573dcc,0x2d13baa5,0x642fc782,
        0xdc4dc65c,0x9571bb7b,0x4e353c12,0x07094135,0xfd504431,0xb46c3916,0x6f28be7f,0x2614c358,
        0x1700aeab,0x5e3cd38c,0x857854e5,0xcc4429c2,0x361d2cc6,0x7f2151e1,0xa465d688,0xed59abaf,
        0x553baa71,0x1c07d756,0xc743503f,0x8e7f2d18,0x7426281c,0x3d1a553b,0xe65ed252,0xaf62af75,
        0x9376a71f,0xda4ada38,0x010e5d51,0x48322076,0xb26b2572,0xfb575855,0x2013df3c,0x692fa21b,
        0xd14da3c5,0x9871dee2,0x4335598b,0x0a0924ac,0xf05021a8,0xb96c5c8f,0x6228dbe6,0x2b14a6c1,
        0x34019664,0x7d3deb43,0xa6796c2a,0xef45110d,0x151c1409,0x5c20692e,0x8764ee47,0xce589360,
        0x763a92be,0x3f06ef99,0xe44268f0,0xad7e15d7,0x572710d3,0x1e1b6df4,0xc55fea9d,0x8c6397ba,
        0xb0779fd0,0xf94be2f7,0x220f659e,0x6b3318b9,0x916a1dbd,0xd856609a,0x0312e7f3,0x4a2e9ad4,
        0xf24c9b0a,0xbb70e62d,0x60346144,0x29081c63,0xd3511967,0x9a6d6440,0x4129e329,0x08159e0e,
        0x3901f3fd,0x703d8eda,0xab7909b3,0xe2457494,0x181c7190,0x51200cb7,0x8a648bde,0xc358f6f9,
        0x7b3af727,0x32068a00,0xe9420d69,0xa07e704e,0x5a27754a,0x131b086d,0xc85f8f04,0x8163f223,
        0xbd77fa49,0xf44b876e,0x2f0f0007,0x66337d20,0x9c6a7824,0xd5560503,0x0e12826a,0x472eff4d,
        0xff4cfe93,0xb67083b4,0x6d3404dd,0x240879fa,0xde517cfe,0x976d01d9,0x4c2986b0,0x0515fb97,
        0x2e015d56,0x673d2071,0xbc79a718,0xf545da3f,0x0f1cdf3b,0x4620a21c,0x9d642575,0xd4585852,
        0x6c3a598c,0x250624ab,0xfe42a3c2,0xb77edee5,0x4d27dbe1,0x041ba6c6,0xdf5f21af,0x96635c88,
        0xaa7754e2,0xe34b29c5,0x380faeac,0x7133d38b,0x8b6ad68f,0xc256aba8,0x19122cc1,0x502e51e6,
        0xe84c5038,0xa1702d1f,0x7a34aa76,0x3308d751,0xc951d255,0x806daf72,0x5b29281b,0x1215553c,
        0x230138cf,0x6a3d45e8,0xb179c281,0xf845bfa6,0x021cbaa2,0x4b20c785,0x906440ec,0xd9583dcb,
        0x613a3c15,0x28064132,0xf342c65b,0xba7ebb7c,0x4027be78,0x091bc35f,0xd25f4436,0x9b633911,
        0xa777317b,0xee4b4c5c,0x350fcb35,0x7c33b612,0x866ab316,0xcf56ce31,0x14124958,0x5d2e347f,
        0xe54c35a1,0xac704886,0x7734cfef,0x3e08b2c8,0xc451b7cc,0x8d6dcaeb,0x56294d82,0x1f1530a5,
    };

    // NOTE: This code is identical to the version above. The only difference is the lookup table
    // for different polynomial. The code is a macro spaghetti enough already so we just repeat the
    // code here to keep things simple.

    inline u32 u8_crc32c(u32 crc, u8 data)
    {
        crc = (crc >> 8) ^ g_crc32c_table[(crc & 0xff) ^ data];
        return crc;
    }

#ifdef MANGO_CPU_64BIT

    // 64 bit crc32c (generic)

    inline u32 u64_crc32c(u32 crc, const u8* ptr)
    {
        u64 data = *reinterpret_cast<const u64le *>(ptr);
        data = data ^ u64(crc);
        crc = g_crc32c_table[((data>>56) & 0xff) + 0x000] ^
              g_crc32c_table[((data>>48) & 0xff) + 0x100] ^
              g_crc32c_table[((data>>40) & 0xff) + 0x200] ^
              g_crc32c_table[((data>>32) & 0xff) + 0x300] ^
              g_crc32c_table[((data>>24) & 0xff) + 0x400] ^
              g_crc32c_table[((data>>16) & 0xff) + 0x500] ^
              g_crc32c_table[((data>> 8) & 0xff) + 0x600] ^
              g_crc32c_table[((data>> 0) & 0xff) + 0x700];
        return crc;
    }

#else

    // 32 bit crc32c (generic)

    inline u32 u64_crc32c(u32 crc, const u8* ptr)
    {
        const u32le* p = reinterpret_cast<const u32le *>(ptr);
#ifdef MANGO_LITTLE_ENDIAN
        u32 one = p[0] ^ crc;
        u32 two = p[1];
#else
        u32 one = p[1] ^ crc;
        u32 two = p[0];
#endif
        crc = g_crc32c_table[((two>>24) & 0xff) + 0x000] ^
              g_crc32c_table[((two>>16) & 0xff) + 0x100] ^
              g_crc32c_table[((two>> 8) & 0xff) + 0x200] ^
              g_crc32c_table[((two>> 0) & 0xff) + 0x300] ^
              g_crc32c_table[((one>>24) & 0xff) + 0x400] ^
              g_crc32c_table[((one>>16) & 0xff) + 0x500] ^
              g_crc32c_table[((one>> 8) & 0xff) + 0x600] ^
              g_crc32c_table[((one>> 0) & 0xff) + 0x700];
        return crc;
    }

#endif // MANGO_CPU_64BIT
#endif // MANGO_HARDWARE_CRC32C

#if defined(MANGO_ENABLE_SSE4_2)

    inline u32 u8_crc32c(u32 crc, u8 data)
    {
        return _mm_crc32_u8(crc, data);
    }

#ifdef MANGO_CPU_64BIT

    // 64 bit crc32c (SSE4.2)

    inline u32 u64_crc32c(u32 crc, const u8* data)
    {
        return u32(_mm_crc32_u64(crc, *reinterpret_cast<const u64 *>(data)));
    }

#else

    // 32 bit crc32c (SSE4.2)
    // (_mm_crc32_u64 is not available in 32 bit x86)

    inline u32 u64_crc32c(u32 crc, const u8* data)
    {
        crc = _mm_crc32_u32(crc, *reinterpret_cast<const u32 *>(data + 0));
        crc = _mm_crc32_u32(crc, *reinterpret_cast<const u32 *>(data + 4));
        return crc;
    }

#endif // MANGO_CPU_64BIT

#elif defined(__ARM_FEATURE_CRC32)

    inline u32 u8_crc32(u32 crc, u8 data)
    {
        return __crc32b(crc, data);
    }

    inline u32 u64_crc32(u32 crc, const u8* data)
    {
        return __crc32d(crc, *reinterpret_cast<const u64 *>(data));
    }

    inline u32 u8_crc32c(u32 crc, u8 data)
    {
        return __crc32cb(crc, data);
    }

    inline u32 u64_crc32c(u32 crc, const u8* data)
    {
        return __crc32cd(crc, *reinterpret_cast<const u64 *>(data));
    }

#endif

    template <typename F8, typename F64>
    inline u32 crc_template(u32 crc, ConstMemory memory, F8 u8_func, F64 u64_func)
    {
        crc = ~crc;

        uintptr_t alignment = (0 - reinterpret_cast<uintptr_t>(memory.address)) & 7;
        if (alignment <= memory.size)
        {
            memory.size -= alignment;
            while (alignment--)
            {
                crc = u8_func(crc, *memory.address++);
            }

            while (memory.size >= 8)
            {
                crc = u64_func(crc, memory.address);
                memory.address += 8;
                memory.size -= 8;
            }
        }

        while (memory.size--)
        {
            crc = u8_func(crc, *memory.address++);
        }

        return ~crc;
    }

} // namespace

namespace mango
{

    u32 crc32(u32 crc, ConstMemory memory)
    {
        return crc_template(crc, memory, u8_crc32, u64_crc32);
    }

    u32 crc32c(u32 crc, ConstMemory memory)
    {
        return crc_template(crc, memory, u8_crc32c, u64_crc32c);
    }

} // namespace mango
